package logic

import (
	"go-programming-tour-book/chatroom/global"
)

// broadcaster 广播器
type broadcaster struct {
	//所有聊天室用户
	users map[string]*User

	//所有channel 统一管理，可以避免外部乱用
	enteringChannel chan *User    //用户进入聊天室时，通过该 channel 告知 Broadcaster，即将该用户加入 Broadcaster 的 users 中
	leavingChannel  chan *User    //用户离开聊天室时，通过该 channel 告知 Broadcaster，即将该用户从 Broadcaster 的 users 中删除，同时需要关闭该用户对应的 messageChannel，避免 goroutine 泄露
	messageChannel  chan *Message //用户发送的消息，通过该 channel 告知 Broadcaster，之后 Broadcaster 将它发送给 users 中的用户

	//判断该昵称用户是否可以进入聊天室（重复与否）：true 能，false 不能
	checkUserChannel      chan string //用来接收用户昵称，方便 Broadcaster 所在 goroutine 能够无锁判断昵称是否存在
	checkUserCanInChannel chan bool   //用来回传该用户昵称是否已经存在
}

//饿汉式单例模式

// Broadcaster 代表广播器的唯一实例，可通过 logic.Broadcaster 来使用这个单例
var Broadcaster = &broadcaster{
	users:                 make(map[string]*User),
	enteringChannel:       make(chan *User),
	leavingChannel:        make(chan *User),
	messageChannel:        make(chan *Message, global.MessageQueueLen),
	checkUserChannel:      make(chan string),
	checkUserCanInChannel: make(chan bool),
}

func (b *broadcaster) CanEnterRoom(nickname string) bool {
	b.checkUserChannel <- nickname

	return <-b.checkUserCanInChannel
}

func (b *broadcaster) UserEntering(u *User) {
	b.enteringChannel <- u
}

func (b *broadcaster) UserLeaving(u *User) {
	b.leavingChannel <- u
}

func (b *broadcaster) Broadcast(msg *Message) {
	b.messageChannel <- msg
}

// Start 启动广播器
// 需要在一个新的 goroutine 中运行，因为它不会返回
func (b *broadcaster) Start() {
	for {
		select {
		case user := <-b.enteringChannel:
			//新用户进入
			b.users[user.NickName] = user

			//b.sendUserList()
			//发送离线消息
			OfflineProcessor.Send(user)
		case user := <-b.leavingChannel:
			//用户离开
			delete(b.users, user.NickName)
			//避免 goroutine 泄露
			user.CloseMessageChannel()

			//b.sendUserList()
		case msg := <-b.messageChannel:
			//if msg.To == "" {
			//	//给所有在线用户发送消息
			//	for _, user := range b.users {
			//		if user.UID == msg.User.UID {
			//			continue
			//		}
			//		user.MessageChannel <- msg
			//	}
			//} else {
			//	if user, ok := b.users[msg.To]; ok {
			//		user.MessageChannel <- msg
			//	} else {
			//		//对方不在线或用户不存在，直接忽略消息
			//		log.Println("user:", msg.To, "not exists!")
			//	}
			//}
			// 给所有在线用户发送消息
			for _, user := range b.users {
				if user.UID == msg.User.UID {
					continue
				}
				user.MessageChannel <- msg
			}
			//存储离线消息
			OfflineProcessor.Save(msg)
		case nickname := <-b.checkUserChannel:
			if _, ok := b.users[nickname]; ok {
				b.checkUserCanInChannel <- false
			} else {
				b.checkUserCanInChannel <- true
			}
		}
	}
}
